package roleservice

import (
	"errors"
	"fmt"
	"strings"
	"time"
	"yunj/pkg/global"
	"yunj/pkg/yunj/core/builder"
	"yunj/pkg/yunj/core/builder/builderconsts"
	"yunj/pkg/yunj/core/builder/builderdto"
	"yunj/pkg/yunj/core/builder/builderenum"
	"yunj/pkg/yunj/core/builder/form"
	"yunj/pkg/yunj/core/builder/form/button"
	"yunj/pkg/yunj/core/builder/form/field"
	"yunj/pkg/yunj/core/builder/table"
	"yunj/pkg/yunj/core/builder/table/col"
	"yunj/pkg/yunj/core/builder/table/col/action"
	"yunj/pkg/yunj/core/builder/table/deftoolbar"
	"yunj/pkg/yunj/core/builder/table/toolbar"
	"yunj/pkg/yunj/util"

	"yunj/pkg/yunj/app/consts"
	"yunj/pkg/yunj/app/data"
	"yunj/pkg/yunj/app/dto"
	"yunj/pkg/yunj/app/enum/admin/authenum"
	"yunj/pkg/yunj/app/enum/stateenum"
	"yunj/pkg/yunj/app/model"
	"yunj/pkg/yunj/app/validator/admin/rolevalidator"

	"github.com/gin-gonic/gin"
	"github.com/worklz/go-validate"
	"gorm.io/gorm"
)

type rolePage struct {
}

var RolePage *rolePage

// 列表构建器
func (s *rolePage) ListBuilder(ctx *gin.Context) *builder.Table {
	return builder.NewTable(ctx, "RoleList").
		State([]builderdto.TableState{
			{Code: stateenum.NORMAL, Title: "正常"},
			{Code: stateenum.RECYLE_BIN, Title: "回收站"},
		}).
		Page(false).
		Filter(field.NewText("keywords", "关键词").SetPlaceholder("模糊匹配，名称/标识")).
		Toolbar(func(t *builder.Table, state *builderdto.TableState) (actions []toolbar.ActionInterface, err error) {
			actions = []toolbar.ActionInterface{
				toolbar.NewOpenPopup("add", "添加").SetClass("layui-icon-add-circle").
					SetUrl(util.BuildAdminUrl("/role/list/add")).SetAuth("yunj_role_list_add"),
			}
			if state.Code == stateenum.RECYLE_BIN {
				actions = append(actions,
					toolbar.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_NORMAL, "恢复正常").SetDropdown(true).SetAuth("yunj_role_list_normal"),
					toolbar.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_DELETED, "永久删除").SetDropdown(true).SetAuth("yunj_role_list_deleted"),
				)
			} else {
				actions = append(actions,
					toolbar.NewOpenPopup(builderenum.TABLE_EVENT_TYPE_SORT, "排序").SetClass("yunj-icon-sort").
						SetUrl(util.BuildAdminUrl("/role/list/sort")).SetAuth("yunj_role_list_sort"),
					toolbar.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_RECYLE_BIN, "移入回收站").SetDropdown(true).SetAuth("yunj_role_list_recyle_bin"),
				)
			}
			return
		}).
		DefaultToolbar([]deftoolbar.ActionInterface{
			deftoolbar.NewFilter(),
			deftoolbar.NewExport().SetAuth("yunj_role_list_export"),
		}).
		Cols(func(t *builder.Table, state *builderdto.TableState) (cols []table.ColInterface, err error) {
			cols = []table.ColInterface{
				col.NewCheckbox("id", "ID"),
				col.NewText("name", "名称"),
				col.NewText("code", "标识"),
				col.NewText("intro", "简介"),
				col.NewTrigger("member_count", "成员数").SetAlign(builderconsts.ALIGN_CENTER).SetMaxWidth(80).
					SetEventType(builderconsts.EVENT_OPEN_TAB).SetEventTitle("成员管理").SetEventUrl(fmt.Sprintf("`%s?role_ids=`+ d.id", util.BuildAdminUrl("/member/list"))),
				col.NewText("auth_count", "权限数").SetAlign(builderconsts.ALIGN_CENTER).SetMaxWidth(80),
			}
			actionCol := col.NewAction("操作").SetOptions([]action.ActionInterface{
				action.NewOpenPopup("edit", "详情").SetClass("layui-icon-survey").SetUrl(util.BuildAdminUrl("/role/list/edit")).SetAuth("yunj_role_list_edit"),
			})
			if state.Code == stateenum.RECYLE_BIN {
				actionCol.Options = append(actionCol.Options,
					action.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_NORMAL, "恢复正常").SetDropdown(true).SetAuth("yunj_role_list_normal"),
					action.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_DELETED, "永久删除").SetDropdown(true).SetAuth("yunj_role_list_deleted").SetConfirmFormFields(field.NewTxt("tips", "确认删除？")).
						SetShow(fmt.Sprintf("d.code!=='%s' && d.id!==%d", consts.ADMINISTRATOR_ROLE_CODE, 1)),
				)
			} else {
				actionCol.Options = append(actionCol.Options,
					action.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_RECYLE_BIN, "移入回收站").SetDropdown(true).SetAuth("yunj_role_list_recyle_bin").
						SetShow(fmt.Sprintf("d.code!=='%s' && d.id!==%d", consts.ADMINISTRATOR_ROLE_CODE, 1)),
				)
			}
			cols = append(cols, actionCol)
			return
		}).
		Validator(func(t *builder.Table) (validate.ValidatorInterface, error) {
			v := &rolevalidator.Role{}
			v.InitValidator(v)
			return v, nil
		}).
		Count(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableCountResult, err error) {
			// 状态数量查询
			query := global.MySQL.Model(&model.AdminRole{})
			var filterFormParam dto.AdminRolePageListFilterFormParam
			util.MapToStruct(requestParam.FilterData(), &filterFormParam)
			s.listBuilderFilterQuery(query, requestParam, &filterFormParam)
			err = query.Count(&res.Count).Error
			if err != nil {
				err = fmt.Errorf("数据量查询异常！%v", err)
				return
			}
			return
		}).
		Items(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableItemsResult, err error) {
			query := global.MySQL.Select("*")
			var filterFormParam dto.AdminRolePageListFilterFormParam
			util.MapToStruct(requestParam.FilterData(), &filterFormParam)
			s.listBuilderFilterQuery(query, requestParam, &filterFormParam)
			if util.Float64ToUints(requestParam.State) != stateenum.RECYLE_BIN {
				query.Order("sort asc")
			} else {
				query.Order("updated_at desc")
			}
			var roleItems []*model.AdminRole
			if err = query.Find(&roleItems).Error; err != nil {
				err = fmt.Errorf("数据查询异常！%v", err)
				return
			}
			res.Items, err = s.listBuilderItemsHandle(roleItems)
			return
		}).
		Event(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableEventResult, err error) {
			handleEventRes, err := builderenum.HandleEvent(ctx, &model.AdminRole{}, requestParam.EventCode, requestParam.Pks, func(param *builderenum.EventDbParam, e *builderenum.Event, pks []any) (err error) {
				if e.Value == builderenum.TABLE_EVENT_TYPE_DELETED {
					param.Data["code"] = gorm.Expr("concat(`code`, '_del_', ?)", time.Now().In(time.Local).Format("20060102150405"))
					param.Where = append(param.Where, []any{"id <> ? and code <> ?", 1, consts.ADMINISTRATOR_ROLE_CODE})
				} else if e.Value == builderenum.TABLE_EVENT_TYPE_RECYLE_BIN {
					param.Where = append(param.Where, []any{"id <> ? and code <> ?", 1, consts.ADMINISTRATOR_ROLE_CODE})
				}
				return
			})
			if err != nil {
				return
			}
			if handleEventRes != nil {
				res.ResponseJsonData = handleEventRes
				return
			}
			err = fmt.Errorf("异常事件[%v]", requestParam.EventCode)
			return
		})
}

type RoleMemberCount struct {
	RoleId      uint64
	MemberCount uint64
}

// 列表数据项处理
func (s *rolePage) listBuilderItemsHandle(items []*model.AdminRole) (resItems []*dto.AdminRolePageListItemResponse, err error) {
	if len(items) <= 0 {
		return
	}
	ids := make([]uint64, 0, len(items))
	for _, v := range items {
		ids = append(ids, v.Id)
	}
	allAuthCount := uint64(len(data.Auth.GetAllAuths())) // 所有权限数
	allAuthMap := data.Auth.GetAllAuthMap()              // 所有权限map
	tablePrefix := global.Config.Database.TablePrefix
	// 成员数
	var roleMemberCounts []*RoleMemberCount
	err = global.MySQL.Table(tablePrefix+"admin_member_role mr").Where(
		"mr.role_id in ? and exists (?)",
		ids,
		global.MySQL.Table(tablePrefix+"admin_member m").Select("1").Where("m.id = mr.member_id and m.state = ?", stateenum.NORMAL),
	).Group("mr.role_id").Select("mr.role_id, count(mr.member_id) as member_count").Find(&roleMemberCounts).Error
	if err != nil {
		err = fmt.Errorf("角色成员数据查询异常！%v", err)
		return
	}
	memberCounts := map[uint64]uint64{}
	for _, roleMemberCount := range roleMemberCounts {
		memberCounts[roleMemberCount.RoleId] = roleMemberCount.MemberCount
	}
	resItems = make([]*dto.AdminRolePageListItemResponse, 0, len(items))
	for _, item := range items {
		resItem := &dto.AdminRolePageListItemResponse{
			Id:    item.Id,
			Name:  item.Name,
			Code:  item.Code,
			Intro: item.Intro,
		}
		// member_count
		if memberCount, exists := memberCounts[item.Id]; exists {
			resItem.MemberCount = memberCount
		}
		// auth_count
		var authCount uint64
		if item.Id == 1 || item.Code == consts.ADMINISTRATOR_ROLE_CODE {
			authCount = allAuthCount
		} else {
			for _, auth := range item.Auths {
				if _, exists := allAuthMap[auth]; exists {
					authCount++
				}
			}
		}
		resItem.AuthCount = authCount
		resItems = append(resItems, resItem)
	}
	return
}

// 列表过滤条件查询对象
func (s *rolePage) listBuilderFilterQuery(query *gorm.DB, requestParam *builderdto.TableRequestParam, filterFormParam *dto.AdminRolePageListFilterFormParam) {
	// ids
	if len(requestParam.Pks) > 0 {
		query.Where("`id` in ?", requestParam.Pks)
	}
	// state
	stateWhere := stateenum.NORMAL
	if stateCode, ok := stateenum.IsValue(requestParam.State); ok {
		stateWhere = stateCode
	}
	query.Where("state = ?", stateWhere)
	// keywords
	if filterFormParam.Keywords != "" {
		keywordsWhere := "%" + filterFormParam.Keywords + "%"
		query.Where("`name` like ? or code like ?", keywordsWhere, keywordsWhere)
	}
}

// 表单构建器
func (s *rolePage) FormBuilder(ctx *gin.Context, isEdit bool) (formBuilder *builder.Form) {
	formBuilder = builder.NewForm(ctx, "RoleForm").
		Field(func(f *builder.Form, tab *builderdto.FormTab) (fields []form.FieldInterface, err error) {
			fields = []form.FieldInterface{
				field.NewText("name", "名称").SetVerify("required|max:100"),
				field.NewText("code", "标识").SetVerify("max:50").SetDesc("全局唯一"),
				field.NewTextarea("intro", "简介").SetVerify("max:200"),
			}
			if isEdit {
				fields = append(fields, field.NewHidden("id"))
				var loadRole dto.AdminRolePageFormLoadResponse
				loadRole, err = builder.FormLoadValue[dto.AdminRolePageFormLoadResponse](f)
				if err != nil {
					return
				}

				if loadRole.Code == consts.ADMINISTRATOR_ROLE_CODE {
					for _, v := range fields {
						if err = v.SetFieldReadonly(true); err != nil {
							err = fmt.Errorf("超管角色设置字段只读异常！%v", err)
							return
						}
					}
				} else {
					// 设置权限选择字段
					fields = s.FormBuilderAuthFieldAppend(fields)
				}
			} else {
				// 设置权限选择字段
				fields = s.FormBuilderAuthFieldAppend(fields)
			}
			// 设置栅格布局
			for _, v := range fields {
				v.SetFieldGrid([]any{12, 6, "6 l3 r3"})
			}
			return
		}).
		Button(func(f *builder.Form) (buttons []form.ButtonInterface, err error) {
			if isEdit {
				var loadRole dto.AdminRolePageFormLoadResponse
				loadRole, err = builder.FormLoadValue[dto.AdminRolePageFormLoadResponse](f)
				if err != nil {
					return
				}

				if loadRole.Id == 1 || loadRole.Code == consts.ADMINISTRATOR_ROLE_CODE {
					// 超管角色不允许修改
					return
				}
				buttons = []form.ButtonInterface{
					button.NewReset(),
					button.NewSubmit(),
				}
			} else {
				buttons = []form.ButtonInterface{
					button.NewClear(),
					button.NewSubmit(),
				}
			}
			return
		}).
		Validator(func(f *builder.Form) (validate.ValidatorInterface, error) {
			v := &rolevalidator.Role{}
			v.InitValidator(v)
			return v, nil
		}).
		Submit(func(f *builder.Form, values map[string]any) (res builderdto.FormSubmitResult, err error) {
			var dbRole *model.AdminRole
			dbRole = util.MapKeyValue(values, "dbRole", dbRole)
			if dbRole.Id > 0 {
				// 修改
				err = global.MySQL.Select("name", "code", "intro", "auths").Save(dbRole).Error
				if err != nil {
					err = fmt.Errorf("编辑失败！%v", err.Error())
					return
				}
			} else {
				// 新增
				err = global.MySQL.Create(dbRole).Error
				if err != nil {
					err = fmt.Errorf("新增失败！%v", err.Error())
					return
				}
			}
			res.Reload = true
			return
		})

	if isEdit {
		formBuilder.Load(func(f *builder.Form) (res any, err error) {
			id := util.QueryUint64Param(ctx, "id")
			if id <= 0 {
				err = fmt.Errorf("异常数据")
				return
			}
			var data model.AdminRole
			dbErr := global.MySQL.Where("`id` = ? and state <> ?", id, stateenum.DELETED).First(&data).Error
			if (dbErr != nil && !errors.Is(dbErr, gorm.ErrRecordNotFound)) || data.Id <= 0 {
				err = fmt.Errorf("数据获取异常！%v", dbErr)
				return
			}
			res = dto.AdminRolePageFormLoadResponse{
				Id:           data.Id,
				Name:         data.Name,
				Code:         data.Code,
				Intro:        data.Intro,
				TopAuths:     data.Auths,
				SidebarAuths: data.Auths,
				OtherAuths:   data.Auths,
			}
			return
		})
	}
	return
}

// 权限选择字段追加
func (s *rolePage) FormBuilderAuthFieldAppend(fields []form.FieldInterface) []form.FieldInterface {
	topNodes, sidebarNodes, otherNodes := s.getAuthFieldTreeNodes()
	if len(topNodes) > 0 {
		fields = append(fields, field.NewTreeCheckbox("top_auths", "顶部菜单权限").SetNodes(topNodes))
	}
	if len(sidebarNodes) > 0 {
		fields = append(fields, field.NewTreeCheckbox("sidebar_auths", "侧边栏菜单权限").SetNodes(sidebarNodes))
	}
	if len(otherNodes) > 0 {
		fields = append(fields, field.NewTreeCheckbox("other_auths", "其他权限").SetNodes(otherNodes))
	}
	return fields
}

// 获取权限字段树节点
func (s *rolePage) getAuthFieldTreeNodes() (topNodes, sidebarNodes, otherNodes []*builderdto.FormTreeCheckNode) {
	allAuths := data.Auth.GetAllAuths()
	// 菜单
	topNodes = []*builderdto.FormTreeCheckNode{}
	sidebarNodes = []*builderdto.FormTreeCheckNode{}
	otherNodes = []*builderdto.FormTreeCheckNode{}
	for _, v := range allAuths {
		if v.ParentKey != "" {
			continue
		}
		switch v.Type {
		case authenum.TYPE_TOP_MENU:
			topNodes = s.getAuthFieldTreeNodesByType(topNodes, v)
		case authenum.TYPE_SIDEBAR_MENU:
			sidebarNodes = s.getAuthFieldTreeNodesByType(sidebarNodes, v)
		case authenum.TYPE_NORMAL:
			otherNodes = s.getAuthFieldTreeNodesByType(otherNodes, v)
		}
	}
	return
}

// 获取指定类型权限字段树节点
func (s *rolePage) getAuthFieldTreeNodesByType(nodes []*builderdto.FormTreeCheckNode, auth *model.AdminAuth) []*builderdto.FormTreeCheckNode {
	nodes = append(nodes, &builderdto.FormTreeCheckNode{
		Id:     auth.Key,
		Pid:    auth.ParentKey,
		Name:   auth.Name,
		HasSub: len(auth.SubAuths) > 0,
	})
	for _, v := range auth.SubAuths {
		nodes = s.getAuthFieldTreeNodesByType(nodes, v)
	}
	return nodes
}

// 下拉搜索选项
func (s *rolePage) DropdownSearchOptions(ctx *gin.Context) (options []builderdto.Option, err error) {
	param := util.QueryParams(ctx)
	query := global.MySQL.Where("state = ?", stateenum.NORMAL).Limit(20).Select("`id`,name,code")
	if values, exists := param["values"]; exists {
		if values, ok := values.(string); ok && values != "" {
			if ids := util.ToUint64Slice(strings.Split(values, ",")); len(ids) > 0 {
				query = query.Where("`id` in ?", ids)
			}
		}
	}
	if keywords, exists := param["keywords"]; exists {
		if keywords, ok := keywords.(string); ok && keywords != "" {
			likeKeywords := "%" + keywords + "%"
			query = query.Where("(`name` like ? or `code` like ?)", likeKeywords, likeKeywords)
		}
	}
	var items []model.AdminRole
	dbErr := query.Find(&items).Error
	if dbErr != nil {
		err = fmt.Errorf("数据查询异常！%v", dbErr)
		return
	}
	options = make([]builderdto.Option, 0, len(items))
	for _, item := range items {
		txt := item.Name
		if item.Code != "" {
			txt += fmt.Sprintf("(%s)", item.Code)
		}
		options = append(options, builderdto.Option{Value: item.Id, Label: txt})
	}
	return
}
